import json
import os
from datetime import datetime, timedelta
import time
from monitor import Monitor, Congestion
from tools.util import get_latest_folder, append_to_csv, get_pass_time
from config import Define
from kafka import KafkaProducer


class ProcessEvent:
    def __init__(self, config_data):
        self.config_data = config_data
        self.format_str = self.config_data["format_str"]
        self.gantry_info = self.config_data["gantry_info"]
        # self.window_length = timedelta(minutes=float(self.gantry_info['time_interval']))
        self.window_length = None
        self.time_move = timedelta(minutes=float(self.gantry_info['time_move']))
        self.route_list = self.config_data["route"]
        # 门架数据
        self.gantry_data = {}
        self.last_type_speed = {}
        # self.last_return_data = {}
        # 实时时间
        self.current_simulated_time = None
        # 时间窗口
        self.start_time = None
        self.end_time = None
        # 接收的最后一帧数据
        self.last_car = None
        # 事件分析
        self.monitor = Monitor(self.config_data["threshold"])
        # 拥堵分析
        self.congestion = Congestion()
        # 线程管理
        self.thread_flag = True
        # 各车型期望通行时间表
        self.type_pass_time = {}
        # 各车型通行时间表
        self.type_pass_time_ture = {}

        # 保存事故数据
        self.save_path = None
        self.save_path1 = None
        self.SAVE = True

        self.kafka_producer = KafkaProducer(
            bootstrap_servers=self.config_data["kafka_host"],
            key_serializer=str.encode,
            value_serializer=lambda x: json.dumps(x).encode('utf-8')
        )


    def init(self):
        self.last_type_speed = {}
        # current_up_list、current_down_list 存储当前时间区间内上下游车辆数量，保存为时间列表
        # up_data_dict、down_data_dict   存储上下游门架数据，保存到以车牌为键的字典
        # detention_dict    滞留车辆字典，暂时未用
        # interval_dict       存储当前时间区间内车辆信息
        # up_vlp_time_dict、down_vlp_time_dict    计算通行率时长字典
        self.gantry_data = {
            "current_up_list": [],
            "current_down_list": [],
            "up_data_dict": {},
            "down_data_dict": {},
            "detention_dict": {},
            "interval_dict": {},
            "up_vlp_time_dict": {},
            "down_vlp_time_dict": {}
        }
        # dd = get_type_pass_time()
        # self.type_pass_time = dd[self.gantry_info["info"]]
        self.type_pass_time = get_pass_time(self.gantry_info["dist"])
        self.window_length = timedelta(minutes=float(self.type_pass_time["1"] * 0.5))
        # self.window_length = timedelta(minutes=float(5))

        folder_path = get_latest_folder(self.config_data["save_path"])
        log_name = "log_" + self.gantry_info["info"] + ".csv"
        log_name1 = "log_" + self.gantry_info["info"] + "_1.csv"
        self.save_path = os.path.join(folder_path, log_name)
        self.save_path1 = os.path.join(folder_path, log_name1)

    def add_message(self, q):
        while not q.empty():
            message = q.get(timeout=0.1)
            # print("收到消息:", message)
            current_time0 = message[Define["TIME"]]
            self.current_simulated_time = datetime.strptime(current_time0, self.format_str)
            if self.start_time is None:
                self.start_time = datetime.strptime(current_time0, self.format_str)
                self.end_time = self.start_time + self.window_length
            gantry_id = message[Define["GANTRY"]]
            if gantry_id == self.gantry_info["up_gantry_id"]:
                current_time = datetime.strptime(message[Define["TIME"]], self.format_str)
                vlp = message[Define["PLATE"]]
                self.gantry_data["current_up_list"].append(current_time)
                self.gantry_data["up_data_dict"][vlp] = {Define["TYPE"]: str(message[Define["TYPE"]]),
                                                         Define["TIME"]: current_time}
                self.gantry_data["interval_dict"][vlp] = {Define["TYPE"]: str(message[Define["TYPE"]]),
                                                          Define["TIME"]: current_time}
            elif gantry_id == self.gantry_info["down_gantry_id"]:
                current_time = datetime.strptime(message[Define["TIME"]], self.format_str)
                vlp = message[Define["PLATE"]]
                self.gantry_data["current_down_list"].append(current_time)
                self.gantry_data["down_data_dict"][vlp] = {Define["TYPE"]: str(message[Define["TYPE"]]),
                                                           Define["TIME"]: current_time}
                self.gantry_data["down_vlp_time_dict"][vlp] = {Define["TYPE"]: str(message[Define["TYPE"]]),
                                                               Define["TIME"]: current_time}
                if vlp in self.gantry_data["interval_dict"].keys():
                    del self.gantry_data["interval_dict"][vlp]

    def expire_clear(self, start_time, end_time, flag=True):
        # 清除过期数据(一小时前未匹配上的上游门架数据)
        # save_time = self.gantry_info["car_pass_time"] + self.config_data["time_move"]
        save_time = 60
        max_pass_time = 0
        if not flag:
            max_pass_time = self.type_pass_time["1"]
        else:
            for i in self.type_pass_time.keys():
                if self.type_pass_time[i] > max_pass_time:
                    max_pass_time = self.type_pass_time[i]
        pass_time = max_pass_time + self.gantry_info["time_move"]
        min_pass_time = max_pass_time * 0.5

        i = 0
        while i < len(self.gantry_data["current_up_list"]):
            if self.gantry_data["current_up_list"][i] < start_time:
                i += 1
            else:
                break
        self.gantry_data["current_up_list"] = self.gantry_data["current_up_list"][i:]
        j = 0
        while j < len(self.gantry_data["current_down_list"]):
            if self.gantry_data["current_down_list"][j] < start_time:
                j += 1
            else:
                break
        self.gantry_data["current_down_list"] = self.gantry_data["current_down_list"][j:]

        # print("过期数据:", i, j)

        del_up_vlp_list = []
        up_vlp_list = list(self.gantry_data["up_data_dict"].keys())
        for vlp in up_vlp_list:
            data_time = self.gantry_data["up_data_dict"][vlp][Define["TIME"]]
            if data_time < end_time - timedelta(minutes=save_time):
                del_up_vlp_list.append(vlp)

        in_vlp_list = []
        self.gantry_data["up_vlp_time_dict"].clear()
        for vlp in up_vlp_list:
            data_time = self.gantry_data["up_data_dict"][vlp][Define["TIME"]]
            if start_time - timedelta(minutes=pass_time) <= data_time < end_time - timedelta(minutes=pass_time):
                in_vlp_list.append(vlp)
        for vlp in in_vlp_list:
            up_vlp = self.gantry_data["up_data_dict"][vlp]
            self.gantry_data["up_vlp_time_dict"][vlp] = {Define["TIME"]: up_vlp[Define["TIME"]],
                                                         Define["TYPE"]: up_vlp[Define["TYPE"]]}

        for vlp in del_up_vlp_list:
            del self.gantry_data["up_data_dict"][vlp]

        del_down_vlp_list = []
        down_vlp_list = list(self.gantry_data["down_data_dict"].keys())
        for vlp in down_vlp_list:
            data_time = self.gantry_data["down_data_dict"][vlp][Define["TIME"]]
            if data_time < start_time:
                del_down_vlp_list.append(vlp)
        for vlp in del_down_vlp_list:
            del self.gantry_data["down_data_dict"][vlp]

        out_vlp_list = []
        out_down_vlp_list = list(self.gantry_data["down_vlp_time_dict"].keys())
        for vlp in out_down_vlp_list:
            data_time = self.gantry_data["down_vlp_time_dict"][vlp][Define["TIME"]]
            if data_time < start_time - timedelta(minutes=pass_time) + timedelta(minutes=min_pass_time):
                out_vlp_list.append(vlp)
        for vlp in out_vlp_list:
            del self.gantry_data["down_vlp_time_dict"][vlp]

    def type_analysis(self, flag=True):
        type_speed_dict = {}
        type_pass_rate_dict = {}
        last_type_pass_time_ture = self.type_pass_time_ture.copy()
        self.type_pass_time_ture = {}
        down_data_dict = self.gantry_data["down_data_dict"].copy()
        up_data_dict = self.gantry_data["up_data_dict"].copy()
        # detention_dict = self.gantry_data["detention_dict"]
        vlp_list = list(down_data_dict.keys())
        for vlp in vlp_list:
            dist = None
            up_time = None
            down_time = down_data_dict[vlp][Define["TIME"]]
            vehicle_type = down_data_dict[vlp][Define["TYPE"]]
            # 查找上游门架对应车牌出现时间，计算平均速度
            if vlp in up_data_dict.keys():
                up_time = up_data_dict[vlp][Define["TIME"]]
                dist = self.gantry_info["dist"]
            if dist is not None:
                dt = down_time - up_time
                dt_seconds = round(dt.total_seconds(), 2)
                dt_hours = dt_seconds / 3600
                speed = round((dist / dt_hours), 2)
                if vlp not in last_type_pass_time_ture.keys():
                    self.type_pass_time_ture[vlp] = {"timestamp": down_time,
                                                     "vtype": vehicle_type,
                                                     "duration": dt.total_seconds()}
                # if vehicle_type == "1" and self.gantry_info["info"] == "10001":
                    # print(self.gantry_info["info"], down_time, vlp, speed)

                if vehicle_type not in type_speed_dict.keys():
                    type_speed_dict[vehicle_type] = {}
                    type_speed_dict[vehicle_type]["speed_list"] = []
                    type_speed_dict[vehicle_type]["slow_level_list"] = []
                type_speed_dict[vehicle_type]["speed_list"].append(speed)

                # if vehicle_type not in type_pass_rate_dict.keys():
                #     type_pass_rate_dict[vehicle_type] = {}
                #     type_pass_rate_dict[vehicle_type]["value"] = []
                #     type_pass_rate_dict[vehicle_type]["vaild_count"] = 0
                #     type_pass_rate_dict[vehicle_type]["count"] = 0
                # type_pass_rate_dict[vehicle_type]["value"].append(int(dt_hours * 60))
                # type_pass_rate_dict[vehicle_type]["count"] += 1

        # 计算平均速度
        for vehicle_type in type_speed_dict.keys():
            speed_list = type_speed_dict[vehicle_type]["speed_list"].copy()
            mean_speed = sum(speed_list) / len(speed_list)
            type_speed_dict[vehicle_type]["mean_speed"] = round(mean_speed, 2)
            self.last_type_speed[vehicle_type] = type_speed_dict[vehicle_type]["mean_speed"]
            type_speed_dict[vehicle_type]["count"] = len(speed_list)
            # 判断是否慢行
            for i in range(len(speed_list)):
                slow_level = 0
                if (speed_list[i] * 3) < mean_speed:
                    slow_level = 4
                elif (speed_list[i] * 2.5) < mean_speed:
                    slow_level = 3
                elif (speed_list[i] * 2) < mean_speed:
                    slow_level = 2
                elif (speed_list[i] * 1.5) < mean_speed:
                    slow_level = 1
                type_speed_dict[vehicle_type]["slow_level_list"].append(slow_level)
            # 统计慢行小客车的数量
            slow_level_list = type_speed_dict[vehicle_type]["slow_level_list"].copy()
            level_0 = slow_level_list.count(0)
            level_1 = slow_level_list.count(1)
            level_2 = slow_level_list.count(2)
            level_3 = slow_level_list.count(3)
            level_4 = slow_level_list.count(4)
            type_speed_dict[vehicle_type]["slow_level_count"] = [level_0, level_1, level_2, level_3, level_4]

        # # 计算通过率
        # car_pass_time = self.gantry_info["car_pass_time"]
        # for vehicle_type in type_pass_rate_dict.keys():
        #     pass_rate_list = type_pass_rate_dict[vehicle_type]["value"].copy()
        #     for i in range(len(pass_rate_list)):
        #         if pass_rate_list[i] <= car_pass_time:
        #             type_pass_rate_dict[vehicle_type]["vaild_count"] += 1

        # 计算通过率
        in_vlp_dict = self.gantry_data["up_vlp_time_dict"].copy()
        for vlp in in_vlp_dict.keys():
            in_time = in_vlp_dict[vlp][Define["TIME"]]
            in_type = in_vlp_dict[vlp][Define["TYPE"]]
            if not flag:
                if in_type != "1":
                    continue
            if in_type not in self.type_pass_time.keys():
                in_type = "0"
            pass_time_config = self.type_pass_time[in_type]
            if in_type not in type_pass_rate_dict.keys():
                type_pass_rate_dict[in_type] = {}
                type_pass_rate_dict[in_type]["count"] = 0
                type_pass_rate_dict[in_type]["pass"] = 0
            type_pass_rate_dict[in_type]["count"] += 1
            if vlp in self.gantry_data["down_vlp_time_dict"].keys():
                out_time = self.gantry_data["down_vlp_time_dict"][vlp][Define["TIME"]]
                pass_time = (out_time - in_time).total_seconds() / 60
                if pass_time <= pass_time_config:
                    type_pass_rate_dict[in_type]["pass"] += 1

        return type_speed_dict, type_pass_rate_dict

    def data_analysis(self, q):
        return_data = {}

        if self.current_simulated_time is not None and self.current_simulated_time > self.end_time:
            i = 0
            for t in self.gantry_data["current_up_list"]:
                if t < self.end_time:
                    i += 1
            j = 0
            for t in self.gantry_data["current_down_list"]:
                if t < self.end_time:
                    j += 1

            # 移动时间窗口
            self.start_time += self.time_move
            self.end_time += self.time_move

            # up_flow_num = len(self.gantry_data["current_up_list"])
            # down_flow_num = len(self.gantry_data["current_down_list"])

            return_data["data"] = {"time": self.end_time - self.time_move,
                                   "up_flow_num": i,
                                   "down_flow_num": j,
                                   "interval_dict": 0,
                                   "type_speed_dict": {},
                                   "type_pass_rate_dict": {}}
            return_data["info"] = self.gantry_info
            return_data["info"]["car_pass_time"] = self.type_pass_time["1"]
            return_data["info"]["time_interval"] = self.window_length
            type_speed_dict, type_pass_rate_dict = self.type_analysis()
            return_data["data"]["type_speed_dict"] = type_speed_dict
            return_data["data"]["type_pass_rate_dict"] = type_pass_rate_dict

            for key in self.gantry_data["interval_dict"].keys():
                end_time = self.end_time - self.time_move
                if self.gantry_data["interval_dict"][key][Define["TIME"]] <= end_time:
                    return_data["data"]["interval_dict"] += 1

            # 清除过期数据(一小时前未匹配上的上游门架数据)
            self.expire_clear(self.start_time, self.end_time)

        # 添加新数据
        self.add_message(q)

        return return_data

    def run(self, q, level):
        # 要添加的表头
        new_row = ['时间', '上游流量', '下游流量', '区间车辆数', '小客车数量', '小客车平均车速', '小客车通过率', '小客车慢行数量',
                   '小客车平均通行时间(s)', '路况', '事故']
        # 调用函数追加新行
        append_to_csv(self.save_path, new_row)
        # 要添加的表头
        new_row1 = ['time', 'flow_change_flag', 'flow_diff', 'flow_diff_p', 'speed_change_flag', 'speed_60_diff', 'current_slow_num',
                    'flow_empty_flag', 'pass_flag', 'current_pass_rate', 'interval_diff', 'block_probability', 'content']
        # 调用函数追加新行
        append_to_csv(self.save_path1, new_row1)
        last_content = None
        last_return_data = None
        while True:
            content = None
            con = None
            return_data = self.data_analysis(q)
            if last_return_data is None and return_data:
                last_return_data = return_data
                continue
            if return_data and last_return_data:
                if return_data != last_return_data:
                    # print(return_data)
                    # print(last_return_data)
                    print("数据更新", self.gantry_info["up_gantry_id"], return_data["data"]["time"])
                    data = return_data
                    last_data = last_return_data
                    last_data["last"] = last_content
                    content, content_info = self.monitor.run(data, last_data)
                    last_content = content

                    if "1" not in self.last_type_speed:
                        mean_speed = self.gantry_info["car_min_speed"]
                    else:
                        mean_speed = self.last_type_speed["1"]
                    con = self.congestion.run(mean_speed)

                    duration_info = []
                    for vlp, vlp_data in self.type_pass_time_ture.items():
                        duration_info.append({"timestamp": vlp_data["timestamp"].strftime("%Y-%m-%dT%H:%M:%S.%f"),
                                              "vtype": vlp_data["vtype"],
                                              "carDuration": vlp_data["duration"]})
                    level_dict = {"畅通": 0, "轻度拥堵": 1, "中度拥堵": 2, "严重拥堵": 3, "阻断": 4, "拥堵+阻断": 5}
                    eventLevel = 0
                    if con == "畅通" and content == "畅通":
                        eventLevel = level_dict[con]
                    elif con != "畅通" and content == "畅通":
                        eventLevel = level_dict[con]
                    elif con == "畅通" and content != "畅通":
                        eventLevel = level_dict[content]
                    else:
                        eventLevel = level_dict["拥堵+阻断"]
                    kafka_data = {
                        "timestamp": return_data["data"]["time"].strftime("%Y-%m-%dT%H:%M:%S.%f"),
                        "sn": self.gantry_info["down_gantry_id"],
                        "congestionFlag": con,
                        "eventFlag": content,
                        "abnormalFlag": "正常",
                        "flowInfo": {
                            "upFlow": return_data["data"]["up_flow_num"],
                            "downFlow": return_data["data"]["down_flow_num"]
                        },
                        "durationInfo": duration_info,
                        "passRateInfo": content_info["current_pass_rate"],
                        "eventLevel": eventLevel
                    }
                    self.kafka_producer.send(self.config_data["kafka_event_index_topic"], value=kafka_data, key="key")
                    # return_data_temp = return_data.copy()
                    # return_data_temp["data"]["time"] = return_data_temp["data"]["time"].strftime("%Y-%m-%d %H:%M:%S")
                    # return_data_temp["info"]["time_interval"] = return_data_temp["info"]["time_interval"].total_seconds()
                    # print(return_data_temp)

                    new_row1 = [return_data["data"]["time"],
                                content_info["flow_change_flag"],
                                content_info["flow_diff"],
                                content_info["flow_diff_p"],
                                content_info["speed_change_flag"],
                                content_info["speed_60_diff"],
                                content_info["current_slow_num"],
                                content_info["flow_empty_flag"],
                                content_info["pass_flag"],
                                content_info["current_pass_rate"],
                                content_info["interval_diff"],
                                content_info["block_probability"],
                                content_info["content"]]
                    # 调用函数追加新行
                    append_to_csv(self.save_path1, new_row1)

                    last_return_data = return_data

            if con is None and content is None:
                continue
            if return_data:
                pass_num = 0
                for k, v in return_data["data"]["type_speed_dict"].items():
                    pass_num += len(v["speed_list"])
                if "1" in return_data["data"]["type_speed_dict"]:
                    car_mean_speed = return_data["data"]["type_speed_dict"]["1"]["mean_speed"]
                else:
                    car_mean_speed = return_data["info"]["car_min_speed"]
                data = {"time": self.current_simulated_time, "con": con, "content": content, "num": pass_num, "speed": car_mean_speed}
                if con != "畅通" or content != "畅通":
                    level.put(data, block=False)

                if self.SAVE:
                    interval_num = 0
                    for key in self.gantry_data["interval_dict"].keys():
                        start_time = self.start_time - self.time_move
                        end_time = self.end_time - self.time_move
                        if start_time <= self.gantry_data["interval_dict"][key][Define["TIME"]] <= end_time:
                            interval_num += 1
                    car_num = 0
                    car_speed = 0
                    car_pass = 0
                    car_slow_num = 0
                    car_pass_time = 0
                    if "1" in return_data["data"]["type_speed_dict"]:
                        car_num = return_data["data"]["type_speed_dict"]["1"]["count"]
                        car_speed = return_data["data"]["type_speed_dict"]["1"]["mean_speed"]
                        num = return_data["data"]["type_speed_dict"]["1"]["slow_level_count"]
                        car_slow_num = num[1] + num[2] + num[3]
                        car_pass_time = self.gantry_info["dist"] / car_speed * 3600
                        car_pass_time = round(car_pass_time, 2)
                    if "1" in return_data["data"]["type_pass_rate_dict"]:
                        car_pass = return_data["data"]["type_pass_rate_dict"]["1"]["pass"] / \
                                   return_data["data"]["type_pass_rate_dict"]["1"]["count"] * 100
                        car_pass = round(car_pass, 2)
                    # 时间，上游流量，下游流量，区间车辆数，客车数量，客车平均车速，客车通过率，客车慢行数量，客车平均通行时间，路况，事故
                    new_row = [return_data["data"]["time"],
                               return_data["data"]["up_flow_num"],
                               return_data["data"]["down_flow_num"],
                               interval_num,
                               car_num,
                               car_speed,
                               car_pass,
                               car_slow_num,
                               car_pass_time,
                               con,
                               content]
                    # 调用函数追加新行
                    append_to_csv(self.save_path, new_row)

            time.sleep(0.1)


def process_main(config_data, q, level):
    """
    主处理函数，负责初始化和执行进程事件。

    参数:
    config_data: 配置数据，用于初始化进程事件。
    q: 队列对象，用于在进程间通信。
    level: 队列对象，用于存储事件结果。
    """
    # 创建ProcessEvent实例，传入配置数据进行初始化
    process_event = ProcessEvent(config_data)
    # 初始化进程事件，进行必要的设置和准备
    process_event.init()
    # 启动进程事件，开始处理任务
    process_event.run(q, level)

